﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.IO;

namespace Locker.FrameWork
{

    public class LoginDetails
    {
        public int IndentityKey { get; set; }
        public string UserNameOrEmail { get; set; }
        public string PasswordHash { get; set; }
    }

    public class ActivatedUsers
    {
        private static LockerDbEntities LockerEntityModel;
        /// <summary>
        /// Check for already exists user.
        /// if user exists redirect to login form
        /// </summary>
        /// <returns>Login details if user exists</returns>
        public static LoginDetails CheckUserAlreadyExists()
        {
            try
            {
                LockerEntityModel = new LockerDbEntities();
                var userExists = LockerEntityModel.LockerLogins.FirstOrDefault();
                if (userExists != null)
                {
                    LoginDetails loginCred = new LoginDetails();
                    loginCred.IndentityKey = userExists.Id;
                    loginCred.UserNameOrEmail = userExists.UserName;
                    loginCred.PasswordHash = SecurityCheck.DecryptPassword(userExists.PasswordHash);
                    return loginCred;
                }
                else
                    return null;
            }
            catch
            {
                throw null;
            }
        }

        /// <summary>
        /// add new user to locker application
        /// </summary>
        /// <param name="loginCred">Current User Details</param>
        /// <returns>true if successfully added</returns>
        public static bool AddNewUserToLocker(LoginDetails loginCred)
        {
            try
            {
                LockerEntityModel = new LockerDbEntities();
                LockerEntityModel.Database.ExecuteSqlCommand("Truncate Table LockerLogin;");
                LockerEntityModel.Database.ExecuteSqlCommand("Truncate Table WebsiteDetails;");
                LockerLogin login = new LockerLogin();
                login.UserName = loginCred.UserNameOrEmail;
                login.PasswordHash = SecurityCheck.EncryptPassword(loginCred.PasswordHash);
                LockerEntityModel.LockerLogins.Add(login);
                LockerEntityModel.SaveChanges();
                return true;
            }
            catch
            {
                return false;
            }
        }

        public static bool AllowLogin(LoginDetails loginDetails)
        {
            try
            {
                string encryptPassword = SecurityCheck.EncryptPassword(loginDetails.PasswordHash);
                LockerEntityModel = new LockerDbEntities();
                LockerLogin locker = LockerEntityModel.LockerLogins.Where((user) => user.UserName == loginDetails.UserNameOrEmail
                    && user.PasswordHash == encryptPassword).FirstOrDefault();
                if (locker != null)
                    return true;
                return false;
            }
            catch
            {
                return false;
            }
        }
    }

    /// <summary>
    /// Should not temper may result in data loss.
    /// </summary>
    public class SecurityCheck
    {
        public static string EncryptPassword(string password)
        {
            string EncryptionKey = "LockerPasswordHashKey";
            byte[] clearBytes = Encoding.Unicode.GetBytes(password);
            using (Aes encryptor = Aes.Create())
            {
                Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(clearBytes, 0, clearBytes.Length);
                        cs.Close();
                    }
                    password = Convert.ToBase64String(ms.ToArray());
                }
            }
            return password;
        }
        public static string DecryptPassword(string cipherText)
        {
            string EncryptionKey = "LockerPasswordHashKey";
            byte[] cipherBytes = Convert.FromBase64String(cipherText);
            using (Aes encryptor = Aes.Create())
            {
                Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(cipherBytes, 0, cipherBytes.Length);
                        cs.Close();
                    }
                    cipherText = Encoding.Unicode.GetString(ms.ToArray());
                }
            }
            return cipherText;
        }
    }
}
